﻿/**
<code>
  <author name="Zealic" email="zealic(at)gmail.com" type="Creator"/>
</code>
**/
using System;


namespace Zealib.Transform
{
    /// <summary>
    /// Strong-typed transformer base class.
    /// </summary>
    /// <typeparam name="TSource">Typed source.</typeparam>
    /// <typeparam name="TDestiation">Typed destiation.</typeparam>
    public abstract class StrongTypedTransformer<TSource, TDestiation> : ITransformer
    {
        /// <summary>
        /// Check can source transform as <typeparamref name="TDestiation"/>.
        /// </summary>
        /// <returns>Always return true.</returns>
        public bool CanTransformTo()
        {
            return true;
        }

        /// <summary>
        /// Check can transform destiation as <typeparamref name="TSource"/>.
        /// </summary>
        /// <typeparam name="TSource">Source type.</typeparam>
        /// <returns>Always return true.</returns>
        public bool CanTransformBack()
        {
            return true;
        }

        /// <summary>
        /// Transform source as <typeparamref name="TDestiation"/>.
        /// </summary>
        /// <typeparam name="TDestiation">Destiation type.</typeparam>
        /// <param name="source">Source object.</param>
        /// <returns>Transformed destiation object.</returns>
        public abstract TDestiation TransformTo(TSource source);

        /// <summary>
        /// Transform destiation as <typeparamref name="TSource"/>.
        /// </summary>
        /// <typeparam name="TSource">Source type.</typeparam>
        /// <param name="destiation">Destiation object.</param>
        /// <returns>Transformed source object.</returns>
        public abstract TSource TransformBack(TDestiation destiation);

        #region ITransformer Members
        bool ITransformer.CanTransformTo<TDest>()
        {
            return CanTransformBack();
        }

        bool ITransformer.CanTransformBack<TSrc>()
        {
            return CanTransformBack();
        }

        TDest ITransformer.TransformTo<TDest>(object source)
        {
            if (source is TSource &&
                typeof (TDestiation) == typeof(TDest))
            {
                // Boxing so as to type cast.
                object dest = TransformTo((TSource)source);
                return (TDest)dest;
            }
            throw new NotSupportedException();
        }

        TSrc ITransformer.TransformBack<TSrc>(object destiation)
        {
            if (destiation is TDestiation &&
                typeof(TSource) == typeof(TSrc))
            {
                // Boxing so as to type cast.
                object src = TransformBack((TDestiation)destiation);
                return (TSrc)src;
            }
            throw new NotSupportedException();
        }

        #endregion

        protected virtual Exception GetTransformToException(object source, Type destinationType)
        {
            if (source == null) throw new ArgumentNullException("source");
            if (destinationType == null) throw new ArgumentNullException("destinationType");
            string myName = GetType().Name;
            string fullName = source.GetType().FullName;
            string destName = destinationType.FullName;
            string msg = string.Format("'{0}' is unable to transform '{1}' to '{2}'.",
                myName, fullName, destName);
            return new NotSupportedException(msg);
        }

        protected virtual Exception GetTransformBackException(object destination, Type sourceType)
        {
            if (destination == null) throw new ArgumentNullException("destination");
            string myName = GetType().Name;
            string fullName = destination.GetType().FullName;
            string srcName = sourceType.FullName;
            string msg = string.Format("'{0}' is unable transform '{1}' back '{2}'.",
                myName, fullName, srcName);
            return new NotSupportedException(msg);
        }

    }
}
